package org.fitweb.files;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.junit.After;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.util.Collection;

import static org.apache.commons.io.FileUtils.*;
import static org.fitweb.files.FileMaker.*;
import static org.fitweb.files.PathFinder.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

public class DirectoryScroungerTest {

    private DirectoryScrounger scrounger = new DirectoryScrounger();
    private FileMaker make = new FileMaker();
    private File source = make.directory(tempDir(), "source");
    private File target = make.directory(tempDir(), "target");

    @After
    public void tidyUpFiles() throws IOException {
        deleteDirectory(target);
    }

    @Test
    public void testFindsAllHtmlFilesInTestInputPath() throws Exception {
        File dir = make.directory(tempDir(), "tempTestDir");
        File subDir = make.directory(dir, "MoreTests");
        File testOne = make.file(dir, "AFitTest.html");
        File notATest = make.file(dir, "NotAFitTest.monkeys");
        File testTwo = make.file(subDir, "AnotherFitTest.html");

        Collection<File> files = relativeFiles(tempDir(), scrounger.locateTests(new File(dir.getCanonicalPath())));
        assertTrue(files.contains(relativeFile(tempDir(), testOne)));
        assertTrue(files.contains(relativeFile(tempDir(), testTwo)));
        assertFalse(files.contains(relativeFile(tempDir(), notATest)));
    }

    @Test
    public void HandlesDodgyDirectoriesWithDecentErrorMessages() throws IOException {
        expectErrorForDirectory("monkeys", "Directory does not exist");
    }

    @Test
    public void copiesDesiredResourcesFromSourceToEmptyTarget() throws Exception {
        File dataDirectory = make.directory(source, "data");
        File styles = make.file(dataDirectory, "styles.css");
        File scripts = make.file(dataDirectory, "scripts.js");
        File test = make.file(dataDirectory, "test.html");
        File java = make.file(dataDirectory, "SomeFixture.java");
        File svn = make.directory(dataDirectory, ".svn");
        File svnFile = make.file(svn, "some.file");

        scrounger.synchronise(source, target);

        Collection<File> relativeFiles = relativeFiles(target, allFilesIn(target));

        assertTrue(relativeFiles.contains(relativeFile(source, styles)));
        assertTrue(relativeFiles.contains(relativeFile(source, scripts)));

        assertFalse(relativeFiles.contains(relativeFile(source, test)));
        assertFalse(relativeFiles.contains(relativeFile(source, svnFile)));
        assertFalse(relativeFiles.contains(relativeFile(source, java)));
    }

    @SuppressWarnings("unchecked")
    private Collection<File> allFilesIn(File target) {
        return (Collection<File>) listFiles(target, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
    }

    @Test
    public void doesNotCopyIfFilesOfSameSizeAndDateAreAlreadyThere() throws Exception {
        FileCopier copier = spy(scrounger);
        scrounger = new DirectoryScrounger(copier);
        File sourceFile = make.file(source, "styles.css");
        File targetFile = new File(target, "styles.css");
        FileUtils.writeStringToFile(sourceFile, "div.monkeys { border: thin solid black; }");

        scrounger.synchronise(source, target);
        scrounger.synchronise(source, target);
        scrounger.synchronise(source, target);

        verify(copier, times(1)).copy(sourceFile, targetFile);
    }

    @Test
    public void doesCopyIfFilesHaveDifferentSizeOrDate() throws Exception {
        FileCopier copier = spy(scrounger);
        scrounger = new DirectoryScrounger(copier);
        File sourceFile = make.file(source, "styles.css");
        File targetFile = new File(target, "styles.css");
        writeStringToFile(sourceFile, "div.monkeys { border: thin solid black; }");

        scrounger.synchronise(source, target);

        makeOld(targetFile);
        scrounger.synchronise(source, target);

        writeStringToFile(targetFile, "div.monkeys { border: none; }");
        scrounger.synchronise(source, target);

        verify(copier, times(3)).copy(sourceFile, targetFile);
    }

    private void makeOld(File file) {
        file.setLastModified(file.lastModified() - 1000);
    }

    private void expectErrorForDirectory(String directory, String errorText) throws IOException {
        try {
            scrounger.locateTests(new File(directory));
        } catch (IllegalArgumentException e) {
            String message = e.getMessage();
            assertTrue("Expected \"" + errorText + "\" but was: \"" + message + "\"", message.contains(errorText));
        }
    }

}
